import cv2
import numpy as np
import tkinter as tk
from tkinter import filedialog, ttk, scrolledtext
import tkinter.messagebox as mb
from PIL import Image, ImageDraw, ImageFont, ImageTk
import pytesseract
from pypinyin import pinyin, Style
import subprocess
import platform

class ImageTool:
    def __init__(self, master):
        self.master = master
        master.title("书法字帖图像处理")
        master.geometry("1100x800")  # 增加高度以容纳识别结果区域

        # 配置Tesseract OCR（根据不同操作系统）
        self.configure_tesseract()

        style = ttk.Style()
        style.configure("TButton",
                        padding=12,
                        relief="ridge",
                        background="#2196F3",
                        foreground="black",
                        font=("华文楷体", 12))
        style.map("TButton",
                 background=[("active", "#646CFF")])

        # 顶部按钮区域
        top_frame = ttk.Frame(master, padding=10)
        top_frame.pack(fill=tk.X)
        
        self.load_btn = ttk.Button(top_frame, text="加载字帖", command=self.load_image)
        self.load_btn.pack(side=tk.LEFT, padx=8)
        
        self.gray_btn = ttk.Button(top_frame, text="灰度图", command=self.show_gray, state=tk.DISABLED)
        self.gray_btn.pack(side=tk.LEFT, padx=8)
        
        self.binary_btn = ttk.Button(top_frame, text="二值化处理", command=self.show_binary, state=tk.DISABLED)
        self.binary_btn.pack(side=tk.LEFT, padx=8)
        
        # 添加腐蚀去噪按钮
        self.erode_btn = ttk.Button(top_frame, text="腐蚀去噪", command=self.apply_erosion, state=tk.DISABLED)
        self.erode_btn.pack(side=tk.LEFT, padx=8)
        
        # 添加膨胀操作按钮
        self.dilate_btn = ttk.Button(top_frame, text="应用膨胀操作", command=self.apply_dilation, state=tk.DISABLED)
        self.dilate_btn.pack(side=tk.LEFT, padx=8)
        
        # 添加中值滤波按钮
        self.median_btn = ttk.Button(top_frame, text="中值滤波去噪", command=self.apply_median_filter, state=tk.DISABLED)
        self.median_btn.pack(side=tk.LEFT, padx=8)
        
        # 添加闭运算按钮
        self.closing_btn = ttk.Button(top_frame, text="闭运算>>填充闭合区域", 
                                     command=self.apply_closing, state=tk.DISABLED)
        self.closing_btn.pack(side=tk.LEFT, padx=8)
        
        # 添加高级边缘检测按钮
        self.canny_btn = ttk.Button(top_frame, text="Canny边缘检测", 
                                   command=self.apply_canny_edge, state=tk.DISABLED)
        self.canny_btn.pack(side=tk.LEFT, padx=8)
        
        # 添加识别书法汉字按钮
        self.recognize_btn = ttk.Button(top_frame, text="识别书法汉字", 
                                       command=self.recognize_chinese, state=tk.DISABLED)
        self.recognize_btn.pack(side=tk.LEFT, padx=8)

        # 参数控制面板
        param_frame = ttk.LabelFrame(master, text="高级处理参数", padding=10)
        param_frame.pack(fill=tk.X, padx=15, pady=5)
        
        # 第一行：腐蚀和膨胀参数
        row1_frame = ttk.Frame(param_frame)
        row1_frame.grid(row=0, column=0, sticky=tk.W)
        
        # 腐蚀参数 (小数，范围0.1-10.0，步进0.1)
        ttk.Label(row1_frame, text="腐蚀核大小:").grid(row=0, column=0, padx=5, sticky=tk.W)
        self.erode_kernel_size_var = tk.DoubleVar(value=3.0)  # 图片中默认值为3.0
        erode_kernel_scale = tk.Scale(
            row1_frame, from_=0.1, to=10.0, resolution=0.1,
            orient=tk.HORIZONTAL, length=120,
            variable=self.erode_kernel_size_var,
            command=lambda v: self.update_float_label(self.erode_kernel_size_label, v))
        erode_kernel_scale.grid(row=0, column=1, padx=5)
        self.erode_kernel_size_label = ttk.Label(row1_frame, text="3.0")
        self.erode_kernel_size_label.grid(row=0, column=2, padx=5)
        
        ttk.Label(row1_frame, text="腐蚀迭代:").grid(row=0, column=3, padx=5, sticky=tk.W)
        self.erode_iterations_var = tk.DoubleVar(value=4.0)  # 图片中默认值为4.0
        erode_iter_scale = tk.Scale(
            row1_frame, from_=0.1, to=10.0, resolution=0.1,
            orient=tk.HORIZONTAL, length=100,
            variable=self.erode_iterations_var,
            command=lambda v: self.update_float_label(self.erode_iterations_label, v))
        erode_iter_scale.grid(row=0, column=4, padx=5)
        self.erode_iterations_label = ttk.Label(row1_frame, text="4.0")
        self.erode_iterations_label.grid(row=0, column=5, padx=5)
        
        # 分割线
        ttk.Separator(row1_frame, orient=tk.VERTICAL).grid(row=0, column=6, padx=10, sticky="ns")
        
        # 膨胀参数 (小数，范围0.1-10.0，步进0.1)
        ttk.Label(row1_frame, text="膨胀核大小:").grid(row=0, column=7, padx=5, sticky=tk.W)
        self.dilate_kernel_size_var = tk.DoubleVar(value=2.5)  # 图片中默认值为2.5
        dilate_kernel_scale = tk.Scale(
            row1_frame, from_=0.1, to=10.0, resolution=0.1,
            orient=tk.HORIZONTAL, length=120,
            variable=self.dilate_kernel_size_var,
            command=lambda v: self.update_float_label(self.dilate_kernel_size_label, v))
        dilate_kernel_scale.grid(row=0, column=8, padx=5)
        self.dilate_kernel_size_label = ttk.Label(row1_frame, text="2.5")
        self.dilate_kernel_size_label.grid(row=0, column=9, padx=5)
        
        ttk.Label(row1_frame, text="膨胀迭代:").grid(row=0, column=10, padx=5, sticky=tk.W)
        self.dilate_iterations_var = tk.DoubleVar(value=5.0)  # 图片中默认值为5.0
        dilate_iter_scale = tk.Scale(
            row1_frame, from_=0.1, to=10.0, resolution=0.1,
            orient=tk.HORIZONTAL, length=100,
            variable=self.dilate_iterations_var,
            command=lambda v: self.update_float_label(self.dilate_iterations_label, v))
        dilate_iter_scale.grid(row=0, column=11, padx=5)
        self.dilate_iterations_label = ttk.Label(row1_frame, text="5.0")
        self.dilate_iterations_label.grid(row=0, column=12, padx=5)
        
        # 第二行：中值滤波和其他参数
        row2_frame = ttk.Frame(param_frame)
        row2_frame.grid(row=1, column=0, sticky=tk.W, pady=(10, 0))
        
        # 中值滤波参数 (小数，范围0.1-50.0，步进0.1)
        ttk.Label(row2_frame, text="中值滤波大小:").grid(row=0, column=0, padx=5, sticky=tk.W)
        self.median_size_var = tk.DoubleVar(value=13.6)  # 图片中默认值为13.6
        median_scale = tk.Scale(
            row2_frame, from_=0.1, to=50.0, resolution=0.1,
            orient=tk.HORIZONTAL, length=150,
            variable=self.median_size_var,
            command=lambda v: self.update_float_label(self.median_size_label, v))
        median_scale.grid(row=0, column=1, padx=5)
        self.median_size_label = ttk.Label(row2_frame, text="13.6")
        self.median_size_label.grid(row=0, column=2, padx=5)
        
        # 文字清晰度参数 (小数，范围0.1-5.0，步进0.1)
        ttk.Label(row2_frame, text="文字清晰度:").grid(row=0, column=3, padx=5, sticky=tk.W)
        self.clarity_var = tk.DoubleVar(value=5.0)  # 图片中默认值为5.0
        clarity_scale = tk.Scale(
            row2_frame, from_=0.1, to=5.0, resolution=0.1,
            orient=tk.HORIZONTAL, length=100,
            variable=self.clarity_var,
            command=lambda v: self.update_float_label(self.clarity_label, v))
        clarity_scale.grid(row=0, column=4, padx=5)
        self.clarity_label = ttk.Label(row2_frame, text="5.0")
        self.clarity_label.grid(row=0, column=5, padx=5)
        
        # 标题字体大小参数 (小数，范围0.1-5.0，步进0.1)
        ttk.Label(row2_frame, text="标题大小:").grid(row=0, column=6, padx=5, sticky=tk.W)
        self.title_size_var = tk.DoubleVar(value=5.0)  # 图片中默认值为5.0
        title_scale = tk.Scale(
            row2_frame, from_=0.1, to=5.0, resolution=0.1,
            orient=tk.HORIZONTAL, length=100,
            variable=self.title_size_var,
            command=lambda v: self.update_float_label(self.title_size_label, v))
        title_scale.grid(row=0, column=7, padx=5)
        self.title_size_label = ttk.Label(row2_frame, text="5.0")
        self.title_size_label.grid(row=0, column=8, padx=5)
        
        # 第三行：闭运算参数
        row3_frame = ttk.Frame(param_frame)
        row3_frame.grid(row=2, column=0, sticky=tk.W, pady=(10, 0))
        
        # 闭运算核大小参数 (小数，范围0.1-15.0，步进0.1)
        ttk.Label(row3_frame, text="闭运算核大小:").grid(row=0, column=0, padx=5, sticky=tk.W)
        self.closing_kernel_size_var = tk.DoubleVar(value=15.0)  # 图片中默认值为15.0
        closing_kernel_scale = tk.Scale(
            row3_frame, from_=0.1, to=15.0, resolution=0.1,
            orient=tk.HORIZONTAL, length=150,
            variable=self.closing_kernel_size_var,
            command=lambda v: self.update_float_label(self.closing_kernel_size_label, v))
        closing_kernel_scale.grid(row=0, column=1, padx=5)
        self.closing_kernel_size_label = ttk.Label(row3_frame, text="15.0")
        self.closing_kernel_size_label.grid(row=0, column=2, padx=5)
        
        # 闭运算迭代次数参数 (小数，范围0.1-10.0，步进0.1)
        ttk.Label(row3_frame, text="闭运算迭代:").grid(row=0, column=3, padx=5, sticky=tk.W)
        self.closing_iterations_var = tk.DoubleVar(value=4.0)  # 图片中默认值为4.0
        closing_iter_scale = tk.Scale(
            row3_frame, from_=0.1, to=10.0, resolution=0.1,
            orient=tk.HORIZONTAL, length=120,
            variable=self.closing_iterations_var,
            command=lambda v: self.update_float_label(self.closing_iterations_label, v))
        closing_iter_scale.grid(row=0, column=4, padx=5)
        self.closing_iterations_label = ttk.Label(row3_frame, text="4.0")
        self.closing_iterations_label.grid(row=0, column=5, padx=5)
        
        # 第四行：边缘检测参数
        row4_frame = ttk.Frame(param_frame)
        row4_frame.grid(row=3, column=0, sticky=tk.W, pady=(10, 0))
        
        # Canny边缘检测参数
        ttk.Label(row4_frame, text="Canny阈值:").grid(row=0, column=0, padx=5, sticky=tk.W)
        self.canny_threshold_var = tk.DoubleVar(value=50.0)  # 图片中默认值为50.0
        canny_threshold_scale = tk.Scale(
            row4_frame, from_=10.0, to=200.0, resolution=5.0,
            orient=tk.HORIZONTAL, length=150,
            variable=self.canny_threshold_var,
            command=lambda v: self.update_float_label(self.canny_threshold_label, v))
        canny_threshold_scale.grid(row=0, column=1, padx=5)
        self.canny_threshold_label = ttk.Label(row4_frame, text="50.0")
        self.canny_threshold_label.grid(row=0, column=2, padx=5)
        
        # 轮廓增强参数
        ttk.Label(row4_frame, text="轮廓强度:").grid(row=0, column=3, padx=5, sticky=tk.W)
        self.contour_strength_var = tk.DoubleVar(value=1.0)  # 图片中默认值为1.0
        contour_strength_scale = tk.Scale(
            row4_frame, from_=0.5, to=3.0, resolution=0.1,
            orient=tk.HORIZONTAL, length=120,
            variable=self.contour_strength_var,
            command=lambda v: self.update_float_label(self.contour_strength_label, v))
        contour_strength_scale.grid(row=0, column=4, padx=5)
        self.contour_strength_label = ttk.Label(row4_frame, text="1.0")
        self.contour_strength_label.grid(row=0, column=5, padx=5)
        
        # 状态栏
        self.status_var = tk.StringVar(value="优化中值滤波完成")
        status_bar = ttk.Label(master, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)
        status_bar.pack(side=tk.BOTTOM, fill=tk.X)

        # 图像显示区域
        self.display_frame = ttk.Frame(master)
        self.display_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)
        
        # 删除识别结果区域代码
        # 识别结果区域（新增）
        # self.result_frame = ttk.LabelFrame(master, text="识别结果字帖", padding=10)
        # self.result_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=5)
        
        # 创建文本显示区域
        # self.result_text = scrolledtext.ScrolledText(self.result_frame, height=8, font=("华文楷体", 14))
        # self.result_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 设置识别结果的初始文本
        # recognition_text = """识别结果将在这里显示。完成图像处理流程后，点击"识别书法汉字"按钮查看结果。"""
        # self.result_text.insert(tk.END, recognition_text)
        # self.result_text.configure(state='disabled')  # 设为只读
        
        # 图像处理状态
        self.image = None
        self.gray_image = None
        self.binary_image = None
        self.eroded_image = None
        self.dilated_image = None
        self.median_image = None
        self.closing_image = None
        self.canny_image = None
        self.last_processed_image = None
        
        # 加载中文字体
        self.font_char = ImageFont.truetype("simsun.ttc", 36) if platform.system() == 'Windows' else ImageFont.load_default()
        self.font_pinyin = ImageFont.truetype("simsun.ttc", 14) if platform.system() == 'Windows' else ImageFont.load_default()
    
    def configure_tesseract(self):
        """配置Tesseract OCR路径（根据不同操作系统）"""
        if platform.system() == 'Windows':
            # Windows系统默认路径
            pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
        elif platform.system() == 'Linux':
            try:
                # Linux系统可能需要安装tesseract
                subprocess.check_output(['which', 'tesseract'])
            except subprocess.CalledProcessError:
                mb.showwarning("警告", "Tesseract OCR未安装，请先安装！")
    
    def update_float_label(self, label, value):
        """更新浮点数值标签，显示一位小数"""
        float_value = float(value)
        label.config(text=f"{float_value:.1f}")
    
    def load_image(self):
        """加载图像文件"""
        file_path = filedialog.askopenfilename(
            filetypes=[("图像文件", "*.jpg;*.jpeg;*.png;*.bmp")],
            title="选择字帖图像"
        )
        if file_path:
            self.status_var.set("正在加载图像...")
            self.master.update()
            
            self.image = cv2.imread(file_path)
            if self.image is None:
                mb.showerror("错误", f"无法加载图像: {file_path}")
                return
            
            self.gray_btn.config(state=tk.NORMAL)
            self.binary_btn.config(state=tk.NORMAL)
            self.canny_btn.config(state=tk.NORMAL)
            self.recognize_btn.config(state=tk.DISABLED)  # 初始禁用识别按钮
            
            # 显示加载的原图
            self.show_image(self.image, "原始图像")
            self.status_var.set("优化中值滤波完成")

    def show_gray(self):
        """显示灰度图像"""
        if self.image is not None:
            self.status_var.set("正在转换为灰度图...")
            self.master.update()
            
            self.gray_image = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)
            
            # 显示灰度图像
            self.show_image(self.gray_image, "灰度图像")
            self.status_var.set("优化中值滤波完成")
            
            # 启用边缘检测和识别按钮
            self.canny_btn.config(state=tk.NORMAL)
            self.recognize_btn.config(state=tk.NORMAL)

    def show_binary(self):
        """显示二值化图像"""
        if self.image is not None:
            self.status_var.set("正在进行二值化处理...")
            self.master.update()
            
            # 如果还没有灰度图，先创建灰度图
            if self.gray_image is None:
                self.gray_image = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)
            
            # 使用自适应阈值二值化
            self.binary_image = cv2.adaptiveThreshold(
                self.gray_image, 255,
                cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                cv2.THRESH_BINARY_INV,
                31, 10
            )
            
            # 显示二值化结果
            self.show_image(self.binary_image, "二值化处理结果")
            self.erode_btn.config(state=tk.NORMAL)
            self.closing_btn.config(state=tk.NORMAL)
            self.status_var.set("优化中值滤波完成")
            
            # 启用边缘检测和识别按钮
            self.canny_btn.config(state=tk.NORMAL)
            self.recognize_btn.config(state=tk.NORMAL)
    
    def apply_erosion(self):
        """优化后的腐蚀去噪操作（使用浮点参数）"""
        if self.binary_image is not None:
            self.status_var.set("正在进行腐蚀去噪处理...")
            self.master.update()
            
            # 获取浮点参数并转换为整数（向上取整）
            kernel_size = int(np.ceil(self.erode_kernel_size_var.get()))
            iterations = int(np.ceil(self.erode_iterations_var.get()))
            
            # 确保核大小为奇数
            if kernel_size % 2 == 0:
                kernel_size += 1
            
            # 创建椭圆形状的核
            kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (kernel_size, kernel_size))
            
            # 应用腐蚀操作
            self.eroded_image = cv2.erode(self.binary_image, kernel, iterations=iterations)
            
            # 显示结果
            self.show_image(self.eroded_image, 
                           f"腐蚀去噪 (核大小={kernel_size}, 迭代={iterations})")
            self.dilate_btn.config(state=tk.NORMAL)
            self.median_btn.config(state=tk.NORMAL)
            self.closing_btn.config(state=tk.NORMAL)
            self.status_var.set("优化中值滤波完成")
            
            # 启用识别按钮
            self.recognize_btn.config(state=tk.NORMAL)
        else:
            mb.showwarning("警告", "请先进行二值化处理")
    
    def apply_dilation(self):
        """优化后的膨胀操作（使用浮点参数）"""
        if self.eroded_image is not None or self.binary_image is not None:
            self.status_var.set("正在应用膨胀操作，突出图像特征...")
            self.master.update()
            
            # 获取源图像（优先使用腐蚀后的图像）
            source_img = self.eroded_image if self.eroded_image is not None else self.binary_image
            
            # 获取浮点参数并转换为整数（向上取整）
            kernel_size = int(np.ceil(self.dilate_kernel_size_var.get()))
            iterations = int(np.ceil(self.dilate_iterations_var.get()))
            
            # 确保核大小为奇数
            if kernel_size % 2 == 0:
                kernel_size += 1
            
            # 创建椭圆形状的极
            kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (kernel_size, kernel_size))
            
            # 应用膨胀操作
            self.dilated_image = cv2.dilate(source_img, kernel, iterations=iterations)
            
            # 显示结果
            self.show_image(self.dilated_image, 
                           f"膨胀操作 (核大小={kernel_size}, 迭代={iterations})")
            self.status_var.set("优化中值滤波完成")
            self.median_btn.config(state=tk.NORMAL)
            self.closing_btn.config(state=tk.NORMAL)
            
            # 启用识别按钮
            self.recognize_btn.config(state=tk.NORMAL)
        else:
            mb.showwarning("警告", "请先进行二值化或腐蚀操作")
    
    def apply_median_filter(self):
        """优化后的中值滤波去除小白点（使用浮点参数）"""
        if self.dilated_image is not None or self.eroded_image is not None or self.binary_image is not None:
            self.status_var.set("正在应用中值滤波去除小白点...")
            self.master.update()
            
            # 获取源图像（优先使用膨胀后的图像）
            if self.dilated_image is not None:
                source_img = self.dilated_image
            elif self.eroded_image is not None:
                source_img = self.eroded_image
            else:
                source_img = self.binary_image
            
            # 获取浮点参数并转换为整数（向上取整）
            median_size = int(np.ceil(self.median_size_var.get()))
            
            # 确保核大小为奇数且大于等于3
            if median_size % 2 == 0:
                median_size += 1
            median_size = max(3, median_size)
            
            # 应用中值滤波
            self.median_image = cv2.medianBlur(source_img, median_size)
            
            # 根据清晰度参数调整文字边缘
            clarity = self.clarity_var.get()
            if clarity > 1.0:
                clarity_kernel_size = min(5, int(np.ceil(clarity)) + 1)
                if clarity_kernel_size % 2 == 0:
                    clarity_kernel_size += 1
                clarity_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, 
                                                          (clarity_kernel_size, clarity_kernel_size))
                self.median_image = cv2.dilate(self.median_image, clarity_kernel, iterations=1)
            
            # 显示结果
            self.show_image(self.median_image, f"中值滤波 (核大小={median_size})")
            self.status_var.set("优化中值滤波完成")
            self.closing_btn.config(state=tk.NORMAL)
            
            # 启用识别按钮
            self.recognize_btn.config(state=tk.NORMAL)
        else:
            mb.showwarning("警告", "请先进行二值化处理")
    
    def apply_closing(self):
        """应用闭运算，填充闭合区域"""
        if self.median_image is not None or self.dilated_image is not None or self.eroded_image is not None or self.binary_image is not None:
            self.status_var.set("正在应用闭运算，填充闭合区域...")
            self.master.update()
            
            # 获取源图像（优先使用最近的图像）
            if self.median_image is not None:
                source_img = self.median_image
            elif self.dilated_image is not None:
                source_img = self.dilated_image
            elif self.eroded_image is not None:
                source_img = self.eroded_image
            else:
                source_img = self.binary_image
            
            # 获取浮点参数并转换为整数（向上取整）
            kernel_size = int(np.ceil(self.closing_kernel_size_var.get()))
            iterations = int(np.ceil(self.closing_iterations_var.get()))
            
            # 确保核大小为奇数
            if kernel_size % 2 == 0:
                kernel_size += 1
            
            # 创建椭圆形状的核
            kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (kernel_size, kernel_size))
            
            # 应用闭运算（先膨胀后腐蚀）
            self.closing_image = cv2.morphologyEx(source_img, cv2.MORPH_CLOSE, kernel, iterations=iterations)
            
            # 显示结果
            self.show_image(self.closing_image, 
                           f"闭运算结果 (核大小={kernel_size}, 迭代={iterations})")
            self.status_var.set("优化中值滤波完成")
            
            # 启用识别按钮
            self.recognize_btn.config(state=tk.NORMAL)
        else:
            mb.showwarning("警告", "请先进行二值化处理")
    
    def apply_canny_edge(self):
        """应用Canny边缘检测，优化书法字迹轮廓，基于闭运算后的图像"""
        self.status_var.set("正在应用Canny边缘检测...")
        self.master.update()
        
        if self.closing_image is not None:
            source_img = self.closing_image
        elif self.gray_image is not None:
            source_img = self.gray_image
        elif self.image is not None:
            source_img = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)
        else:
            mb.showwarning("警告", "请先加载图像")
            return
        
        # 1. 中值滤波去噪
        filtered = cv2.medianBlur(source_img, 5)
        
        # 2. 直方图均衡化增强对比度
        clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8, 8))
        equalized = clahe.apply(filtered)
        
        # 3. 双边滤波保留边缘
        denoised = cv2.bilateralFilter(equalized, d=9, sigmaColor=75, sigmaSpace=75)
        
        # 4. 自适应阈值二值化（Canny前预处理）
        binary = cv2.adaptiveThreshold(
            denoised, 255,
            cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
            cv2.THRESH_BINARY_INV,
            31, 15
        )
        
        # 5. 形态学操作：加强边缘连续性，增加迭代次数
        kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
        enhanced = cv2.dilate(binary, kernel, iterations=2)
        
        # 6. 应用Canny边缘检测
        threshold = self.canny_threshold_var.get()
        edges = cv2.Canny(enhanced, threshold, threshold * 3)
        
        # 7. 增强轮廓线：调整轮廓增强参数，使边缘更粗、更连续
        contour_strength = self.contour_strength_var.get()
        if contour_strength > 1.0:
            dilation_size = int(contour_strength * 3)
            if dilation_size % 2 == 0:
                dilation_size += 1
            contour_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (dilation_size, dilation_size))
            edges = cv2.dilate(edges, contour_kernel, iterations=2)
        
        # 保存Canny结果用于后续OCR识别
        self.canny_image = edges.copy()
        
        # 去除反相处理，保持Canny原始效果（白轮廓黑背景）
        self.show_image(edges, f"Canny边缘检测 (阈值={threshold})")
        
        self.status_var.set("边缘检测完成")
        
        # 启用识别按钮
        self.recognize_btn.config(state=tk.NORMAL)
    
    def recognize_chinese(self):
        """识别书法汉字并生成带拼音的字帖"""
        self.status_var.set("正在识别书法汉字并生成字帖...")
        self.master.update()
        
        # 检查是否有有效的Canny图像
        if self.canny_image is None:
            mb.showwarning("警告", "请先进行Canny边缘检测！")
            return
        
        # 显示识别中的状态
        # self.result_text.configure(state='normal')
        # self.result_text.delete(1.0, tk.END)
        # self.result_text.insert(tk.END, "正在进行书法特征分析...")
        # self.master.update()
        
        # 1. 预处理Canny图像
        inverted = cv2.bitwise_not(self.canny_image)
        _, thresh = cv2.threshold(inverted, 127, 255, cv2.THRESH_BINARY)
        
        # 2. OCR识别汉字
        try:
            # 转换为PIL图像格式
            pil_img = Image.fromarray(thresh)
            # 调用Tesseract识别
            text = pytesseract.image_to_string(pil_img, lang='chi_sim')
            text = text.replace('\n', '').replace(' ', '').strip()
            
            if not text:
                raise ValueError("未识别到有效文字")
        except Exception as e:
            mb.showerror("OCR错误", f"文字识别失败: {str(e)}")
            return
        
        # 3. 结构化文本（10行×10列）
        text_grid = []
        for i in range(10):
            start_idx = i * 10
            end_idx = start_idx + 10
            row_chars = list(text[start_idx:end_idx])
            text_grid.append(row_chars)
        
        # 4. 生成带拼音的字帖
        try:
            # 每个格子尺寸（像素）
            cell_size = 80
            width = len(text_grid[0]) * cell_size
            height = len(text_grid) * cell_size
            
            # 创建白色背景
            canvas = Image.new('RGB', (width, height), color='white')
            draw = ImageDraw.Draw(canvas)
            
            for row_idx, row in enumerate(text_grid):
                for col_idx, char in enumerate(row):
                    # 计算格子坐标
                    x = col_idx * cell_size
                    y = row_idx * cell_size
                    
                    # 绘制绿色边框
                    draw.rectangle(
                        [x, y, x + cell_size, y + cell_size],
                        outline=(0, 128, 0), width=2  # 绿色边框
                    )
                    
                    # 生成拼音
                    py = pinyin(char, style=Style.TONE)[0][0] if char else ''
                    
                    # 绘制汉字（居中）
                    if char and char != '□':
                        # 使用 getbbox() 计算汉字尺寸
                        bbox = self.font_char.getbbox(char)
                        char_w = bbox[2] - bbox[0]  # 文字宽度
                        char_h = bbox[3] - bbox[1]  # 文字高度
                        char_x = x + (cell_size - char_w) // 2
                        char_y = y + (cell_size - char_h) // 2 - 5  # 垂直微调
                        draw.text((char_x, char_y), char, font=self.font_char, fill='black')
                        
                        # 计算拼音尺寸并绘制
                        py = pinyin(char, style=Style.TONE)[0][0]
                        py_bbox = self.font_pinyin.getbbox(py)
                        py_w = py_bbox[2] - py_bbox[0]
                        draw.text((x + (cell_size - py_w) // 2, y + 40),
                                  py, font=self.font_pinyin, fill='gray')
            
            tk_img = ImageTk.PhotoImage(canvas)
            result_window = tk.Toplevel(self.master)
            result_window.title("识别结果字帖")
            result_window.geometry(f"{width}x{height}+100+100")
            result_window.lift()
            result_window.attributes("-topmost", True)
            result_window.after_idle(lambda: result_window.attributes("-topmost", False))
            label = ttk.Label(result_window, image=tk_img)
            label.image = tk_img
            label.pack(expand=True)
            
            self.status_var.set("字帖生成完成！")
            
        except Exception as e:
            messagebox.showerror("绘图错误", f"生成字帖失败: {str(e)}")

    def show_image(self, img, title="图像"):
        """显示图像在主窗口（优化：获取最新尺寸信息）"""
        try:
            # 清空显示区域
            for widget in self.display_frame.winfo_children():
                widget.destroy()
            self.display_frame.update_idletasks()  # 确保尺寸更新
            # 转换颜色空间
            if len(img.shape) == 2:  # 灰度图像
                img_display = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
            else:  # 彩色图像
                img_display = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
            
            # 转换为PIL图像格式
            pil_image = Image.fromarray(img_display)
            
            # 获取显示区域大小
            frame_width = self.display_frame.winfo_width()
            frame_height = self.display_frame.winfo_height()
            
            if frame_width < 10 or frame_height < 10:  # 初始化为默认大小
                frame_width = 700
                frame_height = 500
            
            # 计算缩放比例
            img_width, img_height = pil_image.size
            scale = min(frame_width / img_width, frame_height / img_height, 1)
            new_size = (int(img_width * scale), int(img_height * scale))
            
            # 调整图像大小
            resized_img = pil_image.resize(new_size, Image.LANCZOS)
            tk_image = ImageTk.PhotoImage(resized_img)
            
            # 创建Label并显示图像
            label = ttk.Label(self.display_frame, image=tk_image)
            label.image = tk_image  # 保持引用
            label.pack(expand=True)
            
            # 添加标题（使用title_size参数控制标题大小）
            title_size = int(self.title_size_var.get() * 10)  # 缩放参数
            title_label = ttk.Label(self.display_frame, text=title, 
                                  font=("华文楷体", title_size, "bold"))
            title_label.pack(side=tk.TOP, pady=10)
                
        except Exception as e:
            mb.showerror("显示错误", f"无法显示图像: {str(e)}")

if __name__ == "__main__":
    root = tk.Tk()
    app = ImageTool(root)
    root.mainloop()